#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <getopt.h>
#include "CoreFactory.hpp"

using namespace std;

//#include "./ecga/parameter.hpp"   // parameters for the ECGA
#include "GAframework.hpp"
//#include "SimpleImg.h"
#ifdef ARCH_LOG
	#include "ArchValidator.hpp"
#endif

#ifdef ARCH_CAP
	#include "CaP_Validator.hpp"
#endif

#ifdef ARCH_DCAP
	#include "DistCaPValidator.hpp"
#endif


//#include "SimpleCore.hpp"
#include "MultiPopCoreMT.hpp"
#include "CLController.hpp"




Validator *val;
GAcore *gc;
Controller *c;

CoreFactory *cf;

void sigHandler(int sig_num)
{
	printf("Chiusura...\n");
	delete val;
	delete gc;
	delete c;

	exit(0);
}

void printUsage()
{
printf("Options:\n");
printf("--cnf <file>		-c <file>	:define the configuration file. Default is standard.cnf\n");
printf("--alg <algorithm>	-a <algorithm>	:select the evolutionary algorithm:\n");
printf("						SC		: Simple Core, basic algorithm (default)\n");
printf("						MPC		: Multiple Population Core, with SC\n");
printf("						MPCMT	: MultiThread version of MPC\n");
printf("						MGA		: Messy Genetic Agorithm\n");
printf("						CGA		: Compact Genetic Algorithm\n");
printf("						ECGA	: Extended Compact Genetic Algorithm\n");
printf("--help				-h :Show this help\n");
//printf("--verbose			-v :NOT YET IMPLEMENTED\n");
exit(1);
}

int main(int argc, char **argv)
{
	//default configuration file
	const char *cnf_file="standard.cnf";
	//default evolvable algorithm
	const char *algorithm="SC";
	//buffer variable.
	int next_option;
	//options
	const char* const short_options = "hc:a:v";
	const struct option long_options[] = {
		{ "help"	, 0, NULL, 'h'	},
		{ "cnf"		, 1, NULL, 'c'	},
		{ "alg"		, 1, NULL, 'a'	},
		{ "verbose"	, 0, NULL, 'v'	},
		{ NULL		, 0, NULL, 0	}
		};
		
	do	{
		next_option = getopt_long (argc, argv, short_options,long_options, NULL);
		switch (next_option)
			{
			case 'h':{
				//help case
				printUsage();
				exit(0);
				} break;
			case 'c':{
				//set the configuration file
				cnf_file=optarg;
			} break;
			case 'a':{
				//set the evolvable Algorithm to be used
				algorithm=optarg;
			} break;
			case 'v': break;
			case '-1': break;
			}
		}
	while (next_option != -1);	
		
	//random generator initialization
    srand(time(NULL));
	/*
	 * gs: settings for the Genetic Core
	 * vs: settings for the validator
	 * cs: settings for the controller
	 */
    GAmodSettings gs,vs,cs,params;

	// reading from the configuration file
	gs.read_from_file(cnf_file,"GAcore");
	vs.read_from_file(cnf_file,"Validator");
	cs.read_from_file(cnf_file,"Controller");

	signal(SIGINT,sigHandler);

    try
    {
		//initialization of the validatori
	#ifdef ARCH_LOG
    	val = new ArchValidator(vs);
	#endif

	#ifdef ARCH_CAP
    	val = new CaP_Validator(vs);
	#endif

	#ifdef ARCH_DCAP
    	val = new DistCaPValidator(vs);
	#endif
		//Creation of the Factory object
		cf = new CoreFactory(val,gs);
		//get the right evolvable algorithm core from the factory
		gc = cf->getNewGAcore(algorithm);
		//creation of the controller
        c   = new CLController(gc,cs);
    }
    catch(EHW_Exception &e)
    {
        printf("[ERROR] %s\n",e.msg.c_str());
        exit(1);
    }

    try
    {
		//Execution of the algorithm
        c->start_execution();
		//delete all the items.
		delete val; delete gc; delete c;delete cf;
		
    }
    catch(EHW_Exception &e)
    {
        printf("[ERROR] %s\n",e.msg.c_str());
        exit(1);
    }

	return 0;
}
